Next | Prev | Up | Top | Contents | Index
Initializing Asynchronous I/O
You can initialize asynchronous I/O in either of two ways. One way is simple; the other gives you control over the initialization.
Implicit Initialization
You can initialize asynchronous I/O simply by starting an operation with aio_read(), lio_listio(), or aio_write(). The first such call causes default initialization. This is the only form of initialization described by the POSIX standard. However, in a real-time program you often need to control at least the timing of initialization.
Initializing with aio_sgi_init()
You can take greater control of asynchronous I/O by calling aio_sgi_init() (refer to the aio_sgi_init(3) reference page and to the declarations in /usr/include/aio.h). The argument to this call can be a null pointer, indicating you want default values, or you can pass an aioinit_t structure. The principal fields of this structure specify
- the number of asynchronous processes to execute I/O (aio_threads)
The default is 5 processes; the minimum is 2. Specify 1 more than the number of I/O operations that could reasonably be executed in parallel on the available hardware. For example if you will be doing asynchronous I/O to one disk file and one tape drive, there could be at most two concurrent I/O operations, so there is no need to have more than 3 (1 more than 2) asynchronous processes.
- the number of locks that the asynchronous I/O processes should preallocate (aio_locks)
The default used by aio_init() is 3 locks; the minimum is 1. Specify the maximum number of simultaneous lio_listio(LIO_NOWAIT), aio_fsync(), and aio_suspend() calls that your program could execute concurrently. If in doubt, specify the number of subprocesses your program contains.
- the number of lightweight processes (sprocs) that will be sharing the use of asynchronous I/O (aio_numusers)
The default is 5; the minimum is 2. Specify 1 more than the number of different sproc'd processes that will be requesting asynchronous I/O.
Other fields of the aioinit_t structure such as aio_num and aio_usedba are not used at this time and must be zero. Zero-valued fields are taken as a request for the default for that field. Example 8-1 shows a subroutine to initialize asynchronous I/O, given counts of devices and calling processes.
Example 8-1 : Initializing Asynchronous I/O
int initAIO(int numDevs, int numSprocs, int maxOps)
{
aioinit_t A = {0}; /* ensure zero'd fields */
if (numDevs) /* we do know how many devices */
A.aio_threads = 1+numDevs;
if (numSprocs) /* we do know how many sprocs */
A.aio_locks = A.aio_numusers = 1+numSprocs;
if (maxOps) /* we do know max aiocbs at 1 time */
A.aio_num = maxOps;
return aioinit(&A);
}
When to Initialize
The time at which initialization occurs is important. If you initialize in a process that has been assigned to run on an isolated CPU, the asynchronous I/O processes will also run on that CPU. You probably want the I/O processes to run under normal dispatching on unrestricted CPUs. In that case, the proper sequence of initialization is:
- Open all file descriptors and verify that files and devices are ready.
- Initialize asynchronous I/O. The lightweight processes created by aioinit() inherit the attributes of the calling process, including its current priority and access to open file descriptors.
- Isolate any CPUs that are dedicated to real-time work (see "Restricting a CPU From Scheduled Work")--or create the Frame Schedulers (see "Starting Multiple Schedulers").
- Assign real-time processes to their CPUs.
The asynchronous I/O processes created by aioinit() continue to be scheduled according to their priority in whatever CPUs remain available.
Next | Prev | Up | Top | Contents | Index